Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\compiler\structure.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use std::cell::Cell;
30
use crate::compiler::error::Error;
31
use crate::compiler::r#enum::Enum;
32
use crate::compiler::util::store::name_index;
33
use crate::compiler::util::try2;
34
use crate::compiler::util::types::Name;
35
use crate::compiler::Protocol;
36
use crate::model::protocol::{Description, Endianness};
37
use crate::model::structure::{SimpleType, StructFieldRaw, StructFieldView};
38
use bp3d_debug::trace;
39
use std::fmt::{Display, Formatter};
40
use std::rc::Rc;
41
42
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
43
pub enum FixedFieldType {
44
    Int8,
45
    Int16,
46
    Int32,
47
    Int64,
48
    UInt8,
49
    UInt16,
50
    UInt32,
51
    UInt64,
52
    Float32,
53
    Float64,
54
    Bool,
55
}
56
57
impl Display for FixedFieldType {
58
691
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59
691
        match self {
60
0
            FixedFieldType::Int8 => f.write_str("Int8"),
61
0
            FixedFieldType::Int16 => f.write_str("Int16"),
62
0
            FixedFieldType::Int32 => f.write_str("Int32"),
63
0
            FixedFieldType::Int64 => f.write_str("Int64"),
64
324
            FixedFieldType::UInt8 => f.write_str("UInt8"),
65
77
            FixedFieldType::UInt16 => f.write_str("UInt16"),
66
170
            FixedFieldType::UInt32 => f.write_str("UInt32"),
67
108
            FixedFieldType::UInt64 => f.write_str("UInt64"),
68
12
            FixedFieldType::Float32 => f.write_str("Float32"),
69
0
            FixedFieldType::Float64 => f.write_str("Float64"),
70
0
            FixedFieldType::Bool => f.write_str("Bool"),
71
        }
72
691
    }
73
}
74
75
230
fn map_numeric(
76
230
    ty: SimpleType,
77
230
    signed: FixedFieldType,
78
230
    unsigned: FixedFieldType,
79
230
    float: FixedFieldType,
80
230
) -> Option<FixedFieldType> {
81
230
    match ty {
82
28
        SimpleType::Signed => Some(signed),
83
198
        SimpleType::Unsigned => Some(unsigned),
84
4
        SimpleType::Float => Some(float),
85
0
        _ => None,
86
    }
87
230
}
88
89
impl FixedFieldType {
90
198
    pub fn get_byte_size(&self) -> usize {
91
198
        match self {
92
0
            FixedFieldType::Int8 => 1,
93
0
            FixedFieldType::Int16 => 2,
94
0
            FixedFieldType::Int32 => 4,
95
0
            FixedFieldType::Int64 => 8,
96
90
            FixedFieldType::UInt8 => 1,
97
24
            FixedFieldType::UInt16 => 2,
98
48
            FixedFieldType::UInt32 => 4,
99
36
            FixedFieldType::UInt64 => 8,
100
0
            FixedFieldType::Float32 => 4,
101
0
            FixedFieldType::Float64 => 8,
102
0
            FixedFieldType::Bool => 1,
103
        }
104
198
    }
105
106
6
    pub fn from_min_max_value(min_value: isize, max_value: isize) -> Result<Self, Error> {
107
6
        match min_value < 0 {
108
            true => {
109
2
                let bit_size = if max_value > i32::MAX as isize || min_value < i32::MIN as isize {
  Branch (109:35): [True: 0, False: 2]
  Branch (109:68): [True: 0, False: 2]
  Branch (109:35): [Folded - Ignored]
  Branch (109:68): [Folded - Ignored]
110
0
                    64
111
2
                } else if max_value > i16::MAX as isize || min_value < i16::MIN as isize {
  Branch (111:27): [True: 0, False: 2]
  Branch (111:60): [True: 0, False: 2]
  Branch (111:27): [Folded - Ignored]
  Branch (111:60): [Folded - Ignored]
112
0
                    32
113
2
                } else if max_value > i8::MAX as isize || min_value < i8::MIN as isize {
  Branch (113:27): [True: 0, False: 2]
  Branch (113:59): [True: 0, False: 2]
  Branch (113:27): [Folded - Ignored]
  Branch (113:59): [Folded - Ignored]
114
0
                    16
115
                } else {
116
2
                    8
117
                };
118
2
                Self::from_model(StructFieldRaw::Signed { bits: bit_size })
119
            }
120
            false => {
121
4
                let bit_size = if max_value > u32::MAX as isize {
  Branch (121:35): [True: 0, False: 4]
  Branch (121:35): [Folded - Ignored]
122
0
                    64
123
4
                } else if max_value > u16::MAX as isize {
  Branch (123:27): [True: 0, False: 4]
  Branch (123:27): [Folded - Ignored]
124
0
                    32
125
4
                } else if max_value > u8::MAX as isize {
  Branch (125:27): [True: 0, False: 4]
  Branch (125:27): [Folded - Ignored]
126
0
                    16
127
                } else {
128
4
                    8
129
                };
130
4
                Self::from_model(StructFieldRaw::Unsigned { bits: bit_size })
131
            }
132
        }
133
6
    }
134
135
25
    pub fn from_max_value(max_value: usize) -> Result<Self, Error> {
136
25
        let bit_size = if max_value > u32::MAX as usize {
  Branch (136:27): [True: 0, False: 25]
  Branch (136:27): [Folded - Ignored]
137
0
            64
138
25
        } else if max_value > u16::MAX as usize {
  Branch (138:19): [True: 4, False: 21]
  Branch (138:19): [Folded - Ignored]
139
4
            32
140
21
        } else if max_value > u8::MAX as usize {
  Branch (140:19): [True: 2, False: 19]
  Branch (140:19): [Folded - Ignored]
141
2
            16
142
        } else {
143
19
            8
144
        };
145
25
        Self::from_model(StructFieldRaw::Unsigned { bits: bit_size })
146
25
    }
147
148
253
    pub fn from_model(ty1: StructFieldRaw) -> Result<Self, Error> {
149
253
        let motherfuckingrust = ty1.clone();
150
253
        let ty = ty1.get_simple_type();
151
253
        let bit_size = ty1.get_bit_size();
152
253
        if ty == SimpleType::Boolean {
  Branch (152:12): [True: 12, False: 241]
  Branch (152:12): [Folded - Ignored]
153
12
            Ok(Self::Bool)
154
241
        } else if ty == SimpleType::Float && 
bit_size == 3214
{
  Branch (154:19): [True: 14, False: 227]
  Branch (154:46): [True: 6, False: 8]
  Branch (154:19): [Folded - Ignored]
  Branch (154:46): [Folded - Ignored]
155
6
            Ok(Self::Float32)
156
235
        } else if ty == SimpleType::Float && 
bit_size == 648
{
  Branch (156:19): [True: 8, False: 227]
  Branch (156:46): [True: 4, False: 4]
  Branch (156:19): [Folded - Ignored]
  Branch (156:46): [Folded - Ignored]
157
4
            Ok(Self::Float64)
158
231
        } else if bit_size > 32 && 
bit_size <= 6430
{
  Branch (158:19): [True: 30, False: 201]
  Branch (158:36): [True: 30, False: 0]
  Branch (158:19): [Folded - Ignored]
  Branch (158:36): [Folded - Ignored]
159
30
            map_numeric(ty, Self::Int64, Self::UInt64, Self::Float64).ok_or(Error::UnsupportedType(motherfuckingrust))
160
201
        } else if bit_size > 16 && 
bit_size <= 3250
{
  Branch (160:19): [True: 50, False: 151]
  Branch (160:36): [True: 50, False: 0]
  Branch (160:19): [Folded - Ignored]
  Branch (160:36): [Folded - Ignored]
161
50
            map_numeric(ty, Self::Int32, Self::UInt32, Self::Float64).ok_or(Error::UnsupportedType(motherfuckingrust))
162
151
        } else if bit_size > 8 && 
bit_size <= 1624
{
  Branch (162:19): [True: 24, False: 127]
  Branch (162:35): [True: 24, False: 0]
  Branch (162:19): [Folded - Ignored]
  Branch (162:35): [Folded - Ignored]
163
24
            map_numeric(ty, Self::Int16, Self::UInt16, Self::Float32).ok_or(Error::UnsupportedType(motherfuckingrust))
164
127
        } else if bit_size > 0 && 
bit_size <= 8126
{
  Branch (164:19): [True: 126, False: 1]
  Branch (164:35): [True: 126, False: 0]
  Branch (164:19): [Folded - Ignored]
  Branch (164:35): [Folded - Ignored]
165
126
            map_numeric(ty, Self::Int8, Self::UInt8, Self::Float32).ok_or(Error::UnsupportedType(motherfuckingrust))
166
        } else {
167
1
            Err(Error::UnsupportedBitSize(bit_size))
168
        }
169
253
    }
170
}
171
172
#[derive(Clone, Debug)]
173
pub struct Location {
174
    pub byte_offset: usize,
175
    pub bit_offset: usize,
176
    pub byte_size: usize,
177
    pub bit_size: usize,
178
}
179
180
impl Display for Location {
181
702
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
182
702
        write!(
183
702
            f,
184
702
            "bytes {}..{}, bits {}..{}",
185
702
            self.byte_offset,
186
702
            self.byte_offset + self.byte_size,
187
702
            self.bit_offset,
188
702
            self.bit_offset + self.bit_size
189
702
        )
190
702
    }
191
}
192
193
impl Location {
194
123
    fn from_model(bit_size: usize, bit_offset: usize) -> Self {
195
123
        let byte_offset = bit_offset / 8;
196
123
        Self {
197
123
            byte_offset,
198
123
            bit_offset: bit_offset - byte_offset * 8,
199
123
            bit_size,
200
123
            byte_size: if bit_size % 8 != 0 {
  Branch (200:27): [True: 32, False: 91]
  Branch (200:27): [Folded - Ignored]
201
32
                (bit_size / 8) + 1
202
            } else {
203
91
                bit_size / 8
204
            },
205
        }
206
123
    }
207
}
208
209
#[derive(Clone, Debug)]
210
pub enum FieldRaw {
211
    /// Apply a raw C-like cast (used for unsigned > signed and unsigned > float of same bit size).
212
    Transmute,
213
214
    /// Apply a unsigned > signed cast on a non T-aligned value,
215
    /// the maximum positive value is passed in.
216
    SignedCast(usize),
217
218
    /// Don't do anything special, just return the raw value.
219
    None,
220
}
221
222
impl FieldRaw {
223
13
    pub fn is_none(&self) -> bool {
224
13
        
matches!0
(self, Self::None)
225
13
    }
226
227
113
    fn from_model(ty: SimpleType, bit_size: usize) -> FieldRaw {
228
113
        if ty == SimpleType::Float && 
bit_size != 3214
&&
bit_size != 648
{
  Branch (228:12): [True: 14, False: 99]
  Branch (228:39): [True: 8, False: 6]
  Branch (228:57): [True: 4, False: 4]
  Branch (228:12): [Folded - Ignored]
  Branch (228:39): [Folded - Ignored]
  Branch (228:57): [Folded - Ignored]
229
4
            return FieldRaw::None;
230
109
        }
231
109
        if ty == SimpleType::Signed && 
bit_size != 826
&&
bit_size != 1622
&&
bit_size != 3218
&&
bit_size != 6412
{
  Branch (231:12): [True: 26, False: 83]
  Branch (231:40): [True: 22, False: 4]
  Branch (231:57): [True: 18, False: 4]
  Branch (231:75): [True: 12, False: 6]
  Branch (231:93): [True: 10, False: 2]
  Branch (231:12): [Folded - Ignored]
  Branch (231:40): [Folded - Ignored]
  Branch (231:57): [Folded - Ignored]
  Branch (231:75): [Folded - Ignored]
  Branch (231:93): [Folded - Ignored]
232
10
            let max_value = 1 << (bit_size - 1);
233
10
            FieldRaw::SignedCast(max_value - 1)
234
99
        } else if ty == SimpleType::Unsigned {
  Branch (234:19): [True: 61, False: 38]
  Branch (234:19): [Folded - Ignored]
235
61
            FieldRaw::None
236
        } else {
237
38
            FieldRaw::Transmute
238
        }
239
113
    }
240
}
241
242
#[derive(Clone, Debug)]
243
pub enum FieldView {
244
    /// Apply a float view based on an affine transformation function.
245
    Float { a: f64, b: f64, a_inv: f64, b_inv: f64 },
246
247
    /// Apply an enum view.
248
    Enum(Rc<Enum>),
249
250
    /// Don't do anything special, just return the raw value.
251
    None,
252
}
253
254
impl FieldView {
255
117
    fn from_model(
256
117
        proto: &Protocol,
257
117
        ty: SimpleType,
258
117
        bit_size: usize,
259
117
        value: Option<StructFieldView>,
260
117
    ) -> Result<Self, Error> {
261
13
        match value {
262
7
            Some(StructFieldView::Enum { name }) => {
263
7
                if ty != SimpleType::Unsigned && 
ty != SimpleType::Signed3
{
  Branch (263:20): [True: 3, False: 4]
  Branch (263:50): [True: 1, False: 2]
  Branch (263:20): [Folded - Ignored]
  Branch (263:50): [Folded - Ignored]
264
1
                    return Err(Error::UnsupportedViewType(ty));
265
6
                }
266
6
                let r = proto.enums.get(&name).ok_or(Error::UndefinedReference(name))
?0
;
267
6
                Ok(FieldView::Enum(r.clone()))
268
            }
269
3
            Some(StructFieldView::FloatRange { min, max }) => {
270
3
                if ty != SimpleType::Float {
  Branch (270:20): [True: 1, False: 2]
  Branch (270:20): [Folded - Ignored]
271
1
                    return Err(Error::UnsupportedViewType(ty));
272
2
                }
273
2
                let raw_max: usize = (1 << bit_size) - 1;
274
2
                let a = max / (raw_max as f64);
275
2
                let b = min;
276
2
                let a_inv = 1.0 / a;
277
2
                let b_inv = -b;
278
2
                Ok(FieldView::Float { a, b, a_inv, b_inv })
279
            }
280
3
            Some(StructFieldView::FloatMultiplier { multiplier }) => {
281
3
                if ty != SimpleType::Float {
  Branch (281:20): [True: 1, False: 2]
  Branch (281:20): [Folded - Ignored]
282
1
                    return Err(Error::UnsupportedViewType(ty));
283
2
                }
284
2
                let a = multiplier;
285
2
                let b = 0.0;
286
2
                let a_inv = 1.0 / a;
287
2
                let b_inv = 0.0;
288
2
                Ok(FieldView::Float { a, b, a_inv, b_inv })
289
            }
290
            None => {
291
104
                if ty == SimpleType::Float && 
bit_size != 3211
&&
bit_size != 645
{
  Branch (291:20): [True: 11, False: 93]
  Branch (291:47): [True: 5, False: 6]
  Branch (291:65): [True: 1, False: 4]
  Branch (291:20): [Folded - Ignored]
  Branch (291:47): [Folded - Ignored]
  Branch (291:65): [Folded - Ignored]
292
1
                    return Err(Error::UnsupportedViewType(ty));
293
103
                }
294
103
                Ok(FieldView::None)
295
            }
296
        }
297
117
    }
298
}
299
300
#[derive(Clone, Debug)]
301
pub struct FixedField {
302
    pub bits_type: FixedFieldType,
303
    pub raw_type: FixedFieldType,
304
    pub view_type: FixedFieldType,
305
    pub raw: FieldRaw,
306
    pub view: FieldView,
307
    pub endianness: Endianness,
308
}
309
310
impl Display for FixedField {
311
594
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
312
594
        write!(f, "{}, {} endian", self.bits_type, self.endianness)
313
594
    }
314
}
315
316
#[derive(Clone, Debug)]
317
pub struct FixedArrayField {
318
    pub ty: FixedFieldType,
319
    pub array_len: usize,
320
    pub endianness: Endianness,
321
    pub item_bit_size: usize,
322
}
323
324
impl Display for FixedArrayField {
325
36
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
326
36
        write!(f, "{}[{}], {} endian", self.ty, self.array_len, self.endianness)
327
36
    }
328
}
329
330
#[derive(Clone, Debug)]
331
pub enum FieldType {
332
    Fixed(FixedField),
333
    Array(FixedArrayField),
334
    Struct(Rc<Structure>),
335
}
336
337
impl Display for FieldType {
338
702
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
339
702
        match self {
340
594
            FieldType::Fixed(v) => v.fmt(f),
341
36
            FieldType::Array(v) => v.fmt(f),
342
72
            FieldType::Struct(v) => f.write_str(v.name()),
343
        }
344
702
    }
345
}
346
347
impl FieldType {
348
268
    pub fn as_fixed(&self) -> Option<&FixedField> {
349
268
        match self {
350
268
            FieldType::Fixed(v) => Some(v),
351
0
            _ => None,
352
        }
353
268
    }
354
}
355
356
#[derive(Clone, Debug)]
357
pub struct Field {
358
    pub name: String,
359
    pub loc: Location,
360
    pub description: Option<Description>,
361
    pub ty: FieldType,
362
}
363
364
impl Display for Field {
365
702
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
366
702
        write!(f, "{}: {} ({})", self.name, self.ty, self.loc)
367
702
    }
368
}
369
370
impl Field {
371
131
    fn from_model(
372
131
        proto: &Protocol,
373
131
        fields: &[Field],
374
131
        mut last_bit_offset: usize,
375
131
        value: crate::model::structure::StructField,
376
131
    ) -> Result<(Self, usize), Error> {
377
131
        if (value.raw.is_none() && 
value.item_type.is_none()13
) || (value.raw.is_some() &&
value.item_type.is_some()118
) {
  Branch (377:13): [True: 13, False: 118]
  Branch (377:36): [True: 0, False: 13]
  Branch (377:67): [True: 118, False: 13]
  Branch (377:90): [True: 0, False: 118]
  Branch (377:13): [Folded - Ignored]
  Branch (377:36): [Folded - Ignored]
  Branch (377:67): [Folded - Ignored]
  Branch (377:90): [Folded - Ignored]
378
0
            return Err(Error::BadFieldType);
379
131
        }
380
131
        let (
ty, bit_size123
) = if let Some(
info118
) = value.raw {
  Branch (380:37): [True: 118, False: 13]
  Branch (380:37): [Folded - Ignored]
381
118
            let array_len = value.array_len.unwrap_or(1);
382
118
            if array_len == 0 {
  Branch (382:16): [True: 1, False: 117]
  Branch (382:16): [Folded - Ignored]
383
1
                return Err(Error::ZeroArray);
384
117
            }
385
117
            let mut bit_size = info.get_bit_size();
386
117
            let 
view113
= FieldView::from_model(proto, info.get_simple_type(), bit_size, value.view)
?4
;
387
113
            let raw = FieldRaw::from_model(info.get_simple_type(), bit_size);
388
113
            bit_size *= array_len;
389
113
            let 
ty112
= FixedFieldType::from_model(info)
?1
;
390
112
            if array_len > 1 {
  Branch (390:16): [True: 7, False: 105]
  Branch (390:16): [Folded - Ignored]
391
7
                if (bit_size / array_len) % 8 != 0 {
  Branch (391:20): [True: 1, False: 6]
  Branch (391:20): [Folded - Ignored]
392
1
                    return Err(Error::UnalignedArrayCodec);
393
6
                }
394
6
                (
395
6
                    FieldType::Array(FixedArrayField {
396
6
                        endianness: proto.endianness,
397
6
                        array_len,
398
6
                        ty,
399
6
                        item_bit_size: bit_size / array_len,
400
6
                    }),
401
6
                    bit_size,
402
6
                )
403
            } else {
404
105
                let bits_type = FixedFieldType::from_model(StructFieldRaw::Unsigned { bits: bit_size })
?0
;
405
105
                let raw_type = match (bit_size, ty) {
406
4
                    (32, FixedFieldType::Float32) => FixedFieldType::Float32,
407
4
                    (64, FixedFieldType::Float64) => FixedFieldType::Float64,
408
2
                    (_, FixedFieldType::Float32) => bits_type,
409
2
                    (_, FixedFieldType::Float64) => bits_type,
410
93
                    _ => ty,
411
                };
412
105
                (
413
105
                    FieldType::Fixed(FixedField {
414
105
                        endianness: proto.endianness,
415
105
                        bits_type,
416
105
                        raw_type,
417
105
                        view_type: ty,
418
105
                        view,
419
105
                        raw,
420
105
                    }),
421
105
                    bit_size,
422
105
                )
423
            }
424
        } else {
425
13
            let item_type = unsafe { value.item_type.unwrap_unchecked() };
426
13
            let 
r = try2!12
(proto.structs.get(&item_type) =>
Error::UndefinedReference(item_type)1
);
427
12
            trace!("Solved reference {} => {:?}", item_type, r);
428
12
            (FieldType::Struct(r.clone()), r.bit_size)
429
        };
430
123
        let loc = match value.offset {
431
            None => {
432
119
                let loc = Location::from_model(bit_size, last_bit_offset);
433
119
                last_bit_offset += bit_size;
434
119
                loc
435
            }
436
4
            Some(v) => match v.relative_to {
437
                None => {
438
2
                    let start_bits = v.bits.unwrap_or(0);
439
2
                    let end_bits = start_bits + bit_size;
440
2
                    if end_bits > last_bit_offset {
  Branch (440:24): [True: 0, False: 2]
  Branch (440:24): [Folded - Ignored]
441
0
                        last_bit_offset = end_bits;
442
2
                    }
443
2
                    Location::from_model(bit_size, start_bits)
444
                }
445
2
                Some(name) => {
446
12
                    let 
field2
=
fields.iter().find(2
|v| v.name == name
).ok_or(Error::UndefinedReference(name))2
?0
;
447
2
                    let start_bits = field.loc.bit_offset + v.bits.unwrap_or(0);
448
2
                    let end_bits = start_bits + bit_size;
449
2
                    if end_bits > last_bit_offset {
  Branch (449:24): [True: 0, False: 2]
  Branch (449:24): [Folded - Ignored]
450
0
                        last_bit_offset = end_bits;
451
2
                    }
452
2
                    Location::from_model(bit_size, start_bits)
453
                }
454
            },
455
        };
456
123
        Ok((
457
123
            Self {
458
123
                name: value.name,
459
123
                ty,
460
123
                loc,
461
123
                description: value.description,
462
123
            },
463
123
            last_bit_offset,
464
123
        ))
465
131
    }
466
}
467
468
#[derive(Clone, Debug)]
469
pub struct Structure {
470
    pub name: String,
471
    pub description: Option<Description>,
472
    pub fields: Vec<Field>,
473
    pub byte_size: usize,
474
    pub bit_size: usize,
475
    used_in_header: Cell<bool>
476
}
477
478
impl Structure {
479
8
    pub fn set_used_in_header(&self) {
480
8
        self.used_in_header.set(true);
481
8
    }
482
483
118
    pub fn is_used_in_header(&self) -> bool {
484
118
        self.used_in_header.get()
485
118
    }
486
487
74
    pub fn from_model(proto: &Protocol, value: crate::model::structure::Structure) -> Result<Structure, Error> {
488
74
        let mut fields = Vec::with_capacity(value.fields.len());
489
74
        let mut last_bit_offset = 0;
490
197
        for 
field131
in value.fields {
491
131
            let (
field, new_offset123
) = Field::from_model(proto, &fields, last_bit_offset, field)
?8
;
492
123
            fields.push(field);
493
123
            last_bit_offset = new_offset;
494
        }
495
66
        let s = Structure {
496
66
            name: value.name,
497
66
            description: value.description,
498
66
            fields,
499
66
            bit_size: last_bit_offset,
500
66
            byte_size: if last_bit_offset % 8 != 0 {
  Branch (500:27): [True: 0, False: 66]
  Branch (500:27): [Folded - Ignored]
501
0
                (last_bit_offset / 8) + 1
502
            } else {
503
66
                last_bit_offset / 8
504
            },
505
66
            used_in_header: Cell::new(false)
506
66
        };
507
66
        if s.bit_size == 0 {
  Branch (507:12): [True: 1, False: 65]
  Branch (507:12): [Folded - Ignored]
508
1
            return Err(Error::ZeroStruct);
509
65
        }
510
65
        Ok(s)
511
74
    }
512
}
513
514
name_index!(Structure => name);